


#include "MovableActorBase.h"

#include "ParticleHelper.h"


AMovableActorBase::AMovableActorBase()
{
	PrimaryActorTick.bCanEverTick = true;

	Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
	RootComponent = Mesh;

	Grp_Transform = CreateDefaultSubobject<USceneComponent>(TEXT("Grp_Transform"));
	Grp_Transform->SetupAttachment(RootComponent);
	Grp_Transform->SetAbsolute(false, false, true);

	// ------------------------------------------- Translation ------------------------------------------------
	Grp_Translation = CreateDefaultSubobject<USceneComponent>(TEXT("Grp_Translation"));
	Grp_Translation->SetupAttachment(Grp_Transform);

	Translation_Orig_Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Translation_Orig_Mesh"));
	Translation_Orig_Mesh->SetupAttachment(Grp_Translation);
	ControlHandleMap.Emplace(Translation_Orig_Mesh, FControlHandleInfo{"Translation_Orig",
		ETransformMode::ETM_Translation, ETransformAxes::ECA_Org, EHandlePriority::EHP_First});
	
	Translation_X_Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Translation_X_Mesh"));
	Translation_X_Mesh->SetupAttachment(Grp_Translation);
	ControlHandleMap.Emplace(Translation_X_Mesh, FControlHandleInfo{"Translation_X",
		ETransformMode::ETM_Translation, ETransformAxes::ECA_X, EHandlePriority::EHP_Second});

	Translation_Y_Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Translation_Y_Mesh"));
	Translation_Y_Mesh->SetupAttachment(Grp_Translation);
	ControlHandleMap.Emplace(Translation_Y_Mesh, FControlHandleInfo{"Translation_Y",
		ETransformMode::ETM_Translation, ETransformAxes::ECA_Y, EHandlePriority::EHP_Second});

	Translation_Z_Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Translation_Z_Mesh"));
	Translation_Z_Mesh->SetupAttachment(Grp_Translation);
	ControlHandleMap.Emplace(Translation_Z_Mesh, FControlHandleInfo{"Translation_Z",
		ETransformMode::ETM_Translation, ETransformAxes::ECA_Z, EHandlePriority::EHP_Second});

	Translation_XY_Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Translation_XY_Mesh"));
	Translation_XY_Mesh->SetupAttachment(Grp_Translation);
	ControlHandleMap.Emplace(Translation_XY_Mesh, FControlHandleInfo{"Translation_XY",
		ETransformMode::ETM_Translation, ETransformAxes::ECA_XY, EHandlePriority::EHP_Second});

	Translation_XZ_Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Translation_XZ_Mesh"));
	Translation_XZ_Mesh->SetupAttachment(Grp_Translation);
	ControlHandleMap.Emplace(Translation_XZ_Mesh, FControlHandleInfo{"Translation_XZ",
		ETransformMode::ETM_Translation, ETransformAxes::ECA_XZ, EHandlePriority::EHP_Second});

	Translation_YZ_Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Translation_YZ_Mesh"));
	Translation_YZ_Mesh->SetupAttachment(Grp_Translation);
	ControlHandleMap.Emplace(Translation_YZ_Mesh, FControlHandleInfo{"Translation_YZ",
		ETransformMode::ETM_Translation, ETransformAxes::ECA_YZ, EHandlePriority::EHP_Second});

	// ------------------------------------------- Rotation ------------------------------------------------
	Grp_Rotation = CreateDefaultSubobject<USceneComponent>(TEXT("Grp_Rotation"));
	Grp_Rotation->SetupAttachment(Grp_Transform);

	Rotation_X_Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Rotation_X_Mesh"));
	Rotation_X_Mesh->SetupAttachment(Grp_Rotation);
	ControlHandleMap.Emplace(Rotation_X_Mesh, FControlHandleInfo{"Rotation_X",
		ETransformMode::ETM_Rotation, ETransformAxes::ECA_X, EHandlePriority::EHP_First});

	Rotation_Y_Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Rotation_Y_Mesh"));
	Rotation_Y_Mesh->SetupAttachment(Grp_Rotation);
	ControlHandleMap.Emplace(Rotation_Y_Mesh, FControlHandleInfo{"Rotation_Y",
		ETransformMode::ETM_Rotation, ETransformAxes::ECA_Y, EHandlePriority::EHP_First});

	Rotation_Z_Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Rotation_Z_Mesh"));
	Rotation_Z_Mesh->SetupAttachment(Grp_Rotation);
	ControlHandleMap.Emplace(Rotation_Z_Mesh, FControlHandleInfo{"Rotation_Z",
		ETransformMode::ETM_Rotation, ETransformAxes::ECA_Z, EHandlePriority::EHP_First});

	Rotation_XYZ_Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Rotation_XYZ_Mesh"));
	Rotation_XYZ_Mesh->SetupAttachment(Grp_Rotation);
	ControlHandleMap.Emplace(Rotation_XYZ_Mesh, FControlHandleInfo{"Rotation_XYZ",
		ETransformMode::ETM_Rotation, ETransformAxes::ECA_XYZ, EHandlePriority::EHP_Second});

	Rotation_Screen_Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Rotation_Screen_Mesh"));
	Rotation_Screen_Mesh->SetupAttachment(Grp_Rotation);
	ControlHandleMap.Emplace(Rotation_Screen_Mesh, FControlHandleInfo{"Rotation_Screen",
		ETransformMode::ETM_Rotation, ETransformAxes::ECA_Org, EHandlePriority::EHP_Third});

	// ------------------------------------------- Scale ------------------------------------------------
	Grp_Scale = CreateDefaultSubobject<USceneComponent>(TEXT("Grp_Scale"));
	Grp_Scale->SetupAttachment(Grp_Transform);

	Scale_Orig_Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Scale_Orig_Mesh"));
	Scale_Orig_Mesh->SetupAttachment(Grp_Scale);
	ControlHandleMap.Emplace(Scale_Orig_Mesh, FControlHandleInfo{"Scale_Orig",
		ETransformMode::ETM_Scale, ETransformAxes::ECA_Org, EHandlePriority::EHP_First});

	Scale_X_Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Scale_X_Mesh"));
	Scale_X_Mesh->SetupAttachment(Grp_Scale);
	ControlHandleMap.Emplace(Scale_X_Mesh, FControlHandleInfo{"Scale_X",
		ETransformMode::ETM_Scale, ETransformAxes::ECA_X, EHandlePriority::EHP_Second});

	Scale_Y_Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Scale_Y_Mesh"));
	Scale_Y_Mesh->SetupAttachment(Grp_Scale);
	ControlHandleMap.Emplace(Scale_Y_Mesh, FControlHandleInfo{"Scale_Y",
		ETransformMode::ETM_Scale, ETransformAxes::ECA_Y, EHandlePriority::EHP_Second});

	Scale_Z_Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Scale_Z_Mesh"));
	Scale_Z_Mesh->SetupAttachment(Grp_Scale);
	ControlHandleMap.Emplace(Scale_Z_Mesh, FControlHandleInfo{"Scale_Z",
		ETransformMode::ETM_Scale, ETransformAxes::ECA_Z, EHandlePriority::EHP_Second});

	Scale_XY_Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Scale_XY_Mesh"));
	Scale_XY_Mesh->SetupAttachment(Grp_Scale);
	ControlHandleMap.Emplace(Scale_XY_Mesh, FControlHandleInfo{"Scale_XY",
		ETransformMode::ETM_Scale, ETransformAxes::ECA_XY, EHandlePriority::EHP_Second});

	Scale_XZ_Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Scale_XZ_Mesh"));
	Scale_XZ_Mesh->SetupAttachment(Grp_Scale);
	ControlHandleMap.Emplace(Scale_XZ_Mesh, FControlHandleInfo{"Scale_XZ",
		ETransformMode::ETM_Scale, ETransformAxes::ECA_XZ, EHandlePriority::EHP_Second});

	Scale_YZ_Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Scale_YZ_Mesh"));
	Scale_YZ_Mesh->SetupAttachment(Grp_Scale);
	ControlHandleMap.Emplace(Scale_YZ_Mesh, FControlHandleInfo{"Scale_YZ",
		ETransformMode::ETM_Scale, ETransformAxes::ECA_YZ, EHandlePriority::EHP_Second});
}

void AMovableActorBase::BeginPlay()
{
	Super::BeginPlay();

	SetControlHandleVisible(false, ETransformMode::ETM_Translation);
	SetControlHandleVisible(false, ETransformMode::ETM_Rotation);
	SetControlHandleVisible(false, ETransformMode::ETM_Scale);
	
	GetActorBounds(false, DefaultBound_Orig, DefaultBound_Extend);
}

void AMovableActorBase::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

void AMovableActorBase::SetControlHandleVisible(bool Visi, ETransformMode HandleTranformMode)
{
	for (auto& HandleInfo:ControlHandleMap)
	{
		if (HandleInfo.Value.HandleTranformMode == HandleTranformMode)
		{
			HandleInfo.Key->SetVisibility(Visi);
			if (Visi)
				HandleInfo.Key->SetCollisionEnabled(ECollisionEnabled::Type::QueryOnly);
			else
				HandleInfo.Key->SetCollisionEnabled(ECollisionEnabled::Type::NoCollision);
		}
	}
}

void AMovableActorBase::SetHandleStateHover(UStaticMeshComponent* Handle)
{
	if (FControlHandleInfo* Handleinfo = ControlHandleMap.Find(Handle))
	{
		if (Handle_Hover && Handle_RotationBall)
		{
			if (Handleinfo->HandleTranformMode == ETransformMode::ETM_Rotation)
			{
				if ((Handleinfo->HandleTranformAxes == ETransformAxes::ECA_Org) || (Handleinfo->HandleTranformAxes == ETransformAxes::ECA_XYZ))
				{
					UMaterialInstanceDynamic* InstanceDynamic = Handle->CreateDynamicMaterialInstance(0, Handle_RotationBall);
					InstanceDynamic->SetVectorParameterValue(FName("BaseColor"), FLinearColor::Yellow);
				}
				else
				{
					Handle->CreateDynamicMaterialInstance(0, Handle_Hover);
				}
			}
			else
			{
				Handle->CreateDynamicMaterialInstance(0, Handle_Hover);
			}
		}
	}
}

void AMovableActorBase::ResetHandleState(UStaticMeshComponent* Handle)
{
	if (FControlHandleInfo* Handleinfo = ControlHandleMap.Find(Handle))
	{
		if (Handleinfo->HandleTranformMode == ETransformMode::ETM_Rotation)
		{
			if ((Handleinfo->HandleTranformAxes == ETransformAxes::ECA_Org) || (Handleinfo->HandleTranformAxes == ETransformAxes::ECA_XYZ))
			{
				Handle->CreateDynamicMaterialInstance(0, Handle_RotationBall);
				return;
			}
		}

		switch (Handleinfo->HandleTranformAxes)
		{
		case ETransformAxes::ECA_Org:
			if (Handle_Org)
				Handle->CreateDynamicMaterialInstance(0, Handle_Org);
			break;

		case ETransformAxes::ECA_X:
			if (Handle_X)
				Handle->CreateDynamicMaterialInstance(0, Handle_X);
			break;

		case ETransformAxes::ECA_Y:
			if (Handle_Y)
				Handle->CreateDynamicMaterialInstance(0, Handle_Y);
			break;

		case ETransformAxes::ECA_Z:
			if (Handle_Z)
				Handle->CreateDynamicMaterialInstance(0, Handle_Z);
			break;

		case ETransformAxes::ECA_XY:
			if (Handle_Z)
				Handle->CreateDynamicMaterialInstance(0, Handle_Z);
			break;

		case ETransformAxes::ECA_XZ:
			if (Handle_Y)
				Handle->CreateDynamicMaterialInstance(0, Handle_Y);
			break;

		case ETransformAxes::ECA_YZ:
			if (Handle_X)
				Handle->CreateDynamicMaterialInstance(0, Handle_X);
			break;
		}
	}
}

ETransformMode AMovableActorBase::GetHandleTranformMode(UStaticMeshComponent* Handle) const
{
	const FControlHandleInfo* Handleinfo = ControlHandleMap.Find(Handle);
	checkf(Handleinfo, TEXT("Handle: %s is not Found in ControlHandleMap ---> AMovableActorBase"), *Handle->GetName());

	return Handleinfo->HandleTranformMode;
}

ETransformAxes AMovableActorBase::GetHandleTranformAxes(UStaticMeshComponent* Handle) const
{
	const FControlHandleInfo* Handleinfo = ControlHandleMap.Find(Handle);
	checkf(Handleinfo, TEXT("Handle: %s is not Found in ControlHandleMap ---> AMovableActorBase"), *Handle->GetName());

	return Handleinfo->HandleTranformAxes;
}

EHandlePriority AMovableActorBase::GetHandlePriority(UStaticMeshComponent* Handle) const
{
	const FControlHandleInfo* Handleinfo = ControlHandleMap.Find(Handle);
	checkf(Handleinfo, TEXT("Handle: %s is not Found in ControlHandleMap ---> AMovableActorBase"), *Handle->GetName());

	return Handleinfo->HandlePriority;
}

bool AMovableActorBase::IsControlHandle(UStaticMeshComponent* Handle)
{
	FControlHandleInfo* Handleinfo = ControlHandleMap.Find(Handle);
	
	return Handleinfo ? true : false;
}
